#include "threadPool.h"

typedef struct trains_s{
    int cmd;
    int length;
    char data[1000];
}train_t;
/* Usage: 获取文件名 */
int delimPath(char *abPath,char *prePath,char **pfilename){// /usrname/day01/.../file1
    char delim[2] = "/";
    *pfilename = abPath;
    char tmpPath[1024] = {0};
    //printf("%s\n",*pfilename);
    char *token = strtok(abPath,delim);
    while(token != NULL){
        *pfilename = token;
        // printf("%s\n",*pfilename);
        token = strtok(NULL,delim);
        if(token != NULL){
            strcat(tmpPath,"/");
            strcat(tmpPath,*pfilename);
        }else{
            break;
        }
    }
    if(prePath != NULL){
        strcpy(prePath,tmpPath);
    }
    // printf("%s\n",*pfilename);
    return 0;
}

int recvn(int netfd,void *buf,ssize_t length){// 解决半包问题
    char *p = (char *)buf;
    ssize_t cursize = 0;
    while(cursize < length){
        ssize_t sret = recv(netfd,p + cursize,length - cursize,0);
        cursize += sret;
    }
    return 0;
}

/*Usage: 把文件发给客户端*/ 
int putsFiletoClient(int netfd,const char *virtualPath,char *realPath,char *username,MYSQL *mysql){
    train_t train;
    train.cmd = -1;// 没用
    off_t cursize;
    char path[1024];
    bzero(path,sizeof(path));
    char buf[1024]; 
    bzero(buf,sizeof(buf));
    strcpy(buf,virtualPath);
    char *pfilename;
    delimPath(buf,NULL,&pfilename);
    strcpy(path,realPath);
    strcat(path,pfilename);
    printf("file:%s\n",path);// 得到文件实际存放地址

    bzero(buf,sizeof(buf));
    sprintf(buf,"select * from fileSystem where username = '%s' and type = 'f' and path = '%s'",username,virtualPath)  ;
    int qret = mysql_query(mysql,buf);
    if(qret != 0){
        return -1;
    }
    MYSQL_RES *result = mysql_store_result(mysql);
    mysql_free_result(result);
    int ret = access(path,F_OK);
    if(ret != 0){
        printf("file is not existing!\n");
        return -1;
    }
    int fd = open(path,O_RDWR);//绝对路径打开文件
    printf("fd:%d\n",fd);
    struct stat statbuf;
    fstat(fd,&statbuf);

    printf("before get cursize!\n");
    recvn(netfd,&cursize,sizeof(cursize));// 从客户端获取当前已经传输的大小
    printf("after get cursize,cursize = %ld!\n",cursize);

    printf("filesize = %ld\n",statbuf.st_size - cursize);
    off_t filesize = statbuf.st_size - cursize;// 文件大小
    train.length = sizeof(filesize);
    memcpy(train.data,&filesize,sizeof(off_t));
    printf("%d,%d,%ld\n",train.cmd,train.length,filesize);
    send(netfd,&train,sizeof(train.cmd)+sizeof(train.length)+train.length,MSG_NOSIGNAL);
    printf("after send size.\n");
    // 开始传输
    if(filesize > 100000000){
        ftruncate(fd,filesize);
        char *p =(char *)mmap(NULL,filesize,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
        send(netfd,p+cursize,filesize,MSG_NOSIGNAL);
        munmap(p,filesize);
    }else{
        off_t curSize = cursize;
        sendfile(netfd,fd,&curSize,filesize);// 从cursize继续传输
    }
    // 传输完成 向客户端发送完成信息
    char *filename = NULL;
    delimPath(path,NULL,&filename);
    sprintf(buf,"%s is downloaded!",filename);
    send(netfd,buf,strlen(buf),0);
    close(fd);
    return 0;
}

/*Usage: 接收来自客户端的文件*/ 
int getsFilefromClient(int netfd,const char *virtualPath,const char *realPath,char *username,MYSQL *mysql){// /test1/file1 /.../storage/  
                                                                                                           // printf("join putsFile!\n");
    train_t train;
    struct stat statbuf;
    int fd;
    off_t cursize = 0;
    off_t filesize;
    char path[1024];
    bzero(path,sizeof(path));
    char tmpPath[1024] = {0};
    char buf[1024];
    bzero(buf,sizeof(buf));
    char *filename = NULL;  
    strcpy(path,virtualPath);
    delimPath(path,tmpPath,&filename);
    // 获取文件哈希值
    recv(netfd,buf,sizeof(buf),0);
    char sha[1024] = {0};
    strcpy(sha,buf);

    MYSQL_RES *result;
    MYSQL_ROW row;

    bzero(buf,sizeof(buf));
    sprintf(buf,"select * from fileSystem where fileComment = '%s'",sha);
    int qret = mysql_query(mysql,buf);
    result = mysql_store_result(mysql);
    bzero(buf,sizeof(buf));
    // 秒传
    if(qret == 0){// 该文件已存入服务端
        sprintf(buf,"select * from fileSystem where username = '%s' and fileComment = '%s' and type = 'f' and path = '%s'",username,sha,virtualPath);
        bzero(buf,sizeof(buf));
        qret = mysql_query(mysql,buf);
        mysql_free_result(result);
        result = mysql_store_result(mysql);
        if(qret == 0){// 该虚拟路径已存在 云盘已存入
            train.cmd = 100;
            send(netfd,&train.cmd,sizeof(train.cmd),0);
            mysql_free_result(result);
            return 0;
        }else{// 文件已存入服务端 但虚拟路径不存在
            sprintf(buf,"select id from fileSystem where username = '%s' and type = 'd' and tmpPath = '%s'",username,tmpPath);
            qret = mysql_query(mysql,buf);
            result = mysql_store_result(mysql);

            bzero(buf,sizeof(buf));
            if(qret == 0){// 检查客户端发来的目录存在
                row = mysql_fetch_row(result);
                sprintf(buf,"insert into fileSystem (filename,username,parent_id,filecomment,type,path) values ('%s','%s','%s','%s','%s','%s')",filename,username,row[0],sha,"f",tmpPath);
                qret = mysql_query(mysql,buf);
                if(qret == 0){// 成功写入数据库
                    train.cmd = 101;
                    send(netfd,&train.cmd,sizeof(train.cmd),0);
                    mysql_free_result(result);
                    return 0;
                }else{
                    train.cmd = 102;
                    send(netfd,&train.cmd,sizeof(train.cmd),0);
                    return -1;
                }
            }else{// 路径错误
                train.cmd = 103;
                send(netfd,&train.cmd,sizeof(train.cmd),0);
                return -1;
            }
        }
    }
    // 服务端没有该文件 需要传输
    sprintf(buf,"select id from fileSystem where username = '%s' and type = 'd' and tmpPath = '%s'",username,tmpPath);
    qret = mysql_query(mysql,buf);
    result = mysql_store_result(mysql);
    if(qret != 0){
        train.cmd = 104;
        send(netfd,&train.cmd,sizeof(train.cmd),0);
        return -1;
    }
    train.cmd = 105;// 正常传输
    send(netfd,&train.cmd,sizeof(train.cmd),0);

    bzero(tmpPath,sizeof(tmpPath));
    strcpy(tmpPath,realPath);
    strcat(tmpPath,filename);
    printf("path:%s\n",tmpPath);
    int ret = access(path,F_OK);// 判断文件是否存在
    if(ret == 0){// 断点续传
        printf("Reupload!\n");
        fd = open(path,O_RDWR);
        fstat(fd,&statbuf);
        cursize = statbuf.st_size;
    }else if(ret == -1){
        fd = open(path,O_RDWR|O_CREAT|O_TRUNC,0666);
    }else{
        return -1;
    }
    // printf("before send\n");
    train.cmd = -1;
    train.length = sizeof(cursize);
    memcpy(train.data,&cursize,train.length);
    send(netfd,&train,sizeof(train.cmd)+sizeof(train.length)+train.length,MSG_NOSIGNAL);// 告诉客户端已经传了多少
                                                                                        // printf("after send\n");
    recvn(netfd,&train.cmd,sizeof(train.cmd));
    // printf("cmd: %d",train.cmd);
    recvn(netfd,&train.length,sizeof(train.length));
    recvn(netfd,train.data,train.length);
    memcpy(&filesize,train.data,train.length);
    // printf("filesize = %ld\n",filesize);

    ftruncate(fd,cursize+filesize);
    char *p = (char *)mmap(NULL,cursize+filesize,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
    recvn(netfd,p+cursize,filesize);
    
    // 传输完成
    row = mysql_fetch_row(result);
    sprintf(buf,
            "insert into fileSystem (filename,username,parent_id,filecomment,type,path) values ('%s','%s','%s','%s','%s','%s')",
            filename,username,row[0],sha,"f",tmpPath);
    mysql_free_result(result);
    qret = mysql_query(mysql,buf);
    sprintf(buf,"%s is uploaded!",filename);
    send(netfd,buf,strlen(buf),0);
    close(fd);
    if(qret != 0){
        return -1;
    }
    return 0;
}

int removeFile(int netfd,const char *virtualPath,const char *realPath,char *username,MYSQL *mysql){
    char path[1024];
    bzero(path,sizeof(path));
    char buf[1024];
    bzero(buf,sizeof(buf));
    char tmpPath[1024] = {0};
    char sha[1024] = {0};
    char *filename = NULL;
    MYSQL_RES *result;
    MYSQL_ROW row;
    strcpy(path,virtualPath);
    delimPath(path,tmpPath,&filename);
    sprintf(buf,"select fileComment from fileSystem where username = '%s' and type = 'f' and path = '%s'",username,virtualPath);
    int pret = mysql_query(mysql,buf);
    if(pret != 0){
        printf("wrong path!\n");
        return -1;
    }
    result = mysql_store_result(mysql);
    row = mysql_fetch_row(result);

    bzero(buf,sizeof(buf));
    strcpy(sha,row[0]);
    mysql_free_result(result);
    sprintf(buf,"select from fileSystem where fileComment = '%s'",sha);
    pret = mysql_query(mysql,buf);
    if(pret != 0){
        return -1;
    }
    result = mysql_store_result(mysql);
    int fileNum = mysql_num_rows(result);
    if(fileNum == 1){// 这里已经只剩下一处使用这个文件了，可以删除真实文件
        bzero(tmpPath,sizeof(tmpPath));
        strcpy(tmpPath,realPath);
        strcat(tmpPath,filename);
        remove(tmpPath);
    }
    mysql_free_result(result);
    bzero(buf,sizeof(buf));
    sprintf(buf,"delete from fileSystem where username = '%s' and fileComment = '%s' and type = 'f' and path = '%s'",username,sha,virtualPath);
    pret = mysql_query(mysql,buf);
    if(pret != 0){
        return -1;
    }
    bzero(buf,sizeof(buf));
    sprintf(buf,"%s is deleted!",filename);
    send(netfd,buf,strlen(buf),0);
    return 0;
}
